1 /*
2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021
3 License:   [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License].
4 Authors: Marcelo S. N. Mancini
5 
6 	Copyright Marcelo S. N. Mancini 2018 - 2021.
7 Distributed under the CC BY-4.0 License.
8    (See accompanying file LICENSE.txt or copy at
9 	https://creativecommons.org/licenses/by/4.0/
10 */
11 module hip.systems.gameobject;
12 
13 version(none):
14 version(HIPREME_DEBUG){import hip.error.handler;}
15 
16 abstract class HipComponent
17 {
18     package bool hasStarted = false;
19     private HipGameObject _owner;
20     abstract void onStart();
21     private void _onStart(HipGameObject go)
22     {
23         hasStarted = true;
24         _owner = go;
25         onStart();
26     }
27 
28     pragma(inline)
29     protected HipGameObject owner(){return _owner;} 
30 
31     pragma(inline, true)
32     public T getComponent(T)(){return _owner.getComponent!T;}
33 
34 
35     abstract void onRemove();
36     abstract void update(float deltaTime);
37 }
38 
39 class HipSpriteRendererComponent : HipComponent
40 {
41     import hip.graphics.g2d.sprite;
42     import hip.graphics.g2d.spritebatch;
43 
44     HipSpriteBatch batch;
45     HipSprite sprite;
46 
47     struct SpriteData
48     {
49         HipSpriteBatch batch;
50         HipSprite sprite;
51     }
52 
53     void startWithData(void* data)
54     {
55         auto s = *cast(SpriteData*)data;
56         batch  = s.batch;
57         sprite = s.sprite;
58     }
59 
60     override void update(float delta)
61     {
62         batch.draw(sprite);
63     }
64 }
65 
66 mixin template ComponentSpecialization(T)
67 {
68     mixin("T[] " ~ T.stringof~"Components;");
69 
70     HipComponent addComponent(T : HipComponent)()
71     {
72         T comp = new T();
73         mixin(T~"Components~= comp;");
74         return comp;
75     }
76 }
77 
78 
79 
80 private __gshared ulong idCounter = 0;
81 
82 class HipGameObject
83 {
84     ulong id;
85     string tag;
86     bool isActive = true;
87 
88     public HipGameObject parent;
89     public HipGameObject[] children;
90     protected HipComponent[] components;
91 
92     mixin ComponentSpecialization!(HipSpriteRendererComponent);
93 
94     final public void addChild(HipGameObject go)
95     {
96         children~= go;
97         go.parent = this;
98     }
99 
100     final public this(string tag)
101     {
102         id = ++idCounter;
103         this.tag = tag;
104     }
105 
106 
107     HipComponent addComponent(T : HipComponent)()
108     {
109         T comp = new T();
110         components~= comp;
111         return comp;
112     }
113     T getComponent(T : HipComponent)()
114     {
115         foreach(c; components)
116         {
117             T ret = cast(T)c;
118             if(ret !is null)
119                 return ret;
120         }
121         return null;
122     }
123 
124     void removeComponent(T)()
125     {
126         foreach (ulong index, HipComponent c; components)
127         {
128             if(cast(T)c !is null)
129             {
130                 components[index] = components[$-1];
131                 components.length--;
132                 return;
133             }
134         }
135         version(HIPREME_DEBUG)
136             ErrorHandler.showErrorMessage("Removing component", tag~" has no component '"~T.stringof~"'");
137     }
138 
139     void update(float deltaTime)
140     {
141         if(!isActive)
142             return;
143         foreach(c; components)
144         {
145             if(!c.hasStarted)
146                 c._onStart(this);
147             c.update(deltaTime);
148         }
149         foreach(child; children)
150             child.update(deltaTime);
151     }
152 }